Trò chơi Tic-Tac-Toe, game đánh caro full source code
- CubeInter.cs
- DemoSynchronization /
- Demos /
- Photon Unity Networking /
- Assets /
- project /
2 using Hashtable = ExitGames.Client.Photon.Hashtable;
3
4 [RequireComponent(typeof(PhotonView))]
5 public class CubeInter : Photon.MonoBehaviour
6 {
7
8 //
9 // NOTE: Network interpolation is affected by the network sendRate.
10 // By default this is 10 times/second for OnSerialize. (See PhotonNetwork.sendIntervalOnSerialize)
11 // Raise the sendrate if you want to lower the interpolationBackTime.
12 //
13
14 public double interpolationBackTime = 0.15;
15
16 internal struct State
17 {
18 internal double timestamp;
19 internal Vector3 pos;
20 internal Quaternion rot;
21 }
22
23 // We store twenty states with "playback" information
24 State[] m_BufferedState = new State[20];
25 // Keep track of what slots are used
26 int m_TimestampCount;
27
28 void Awake()
29 {
30 if (photonView.isMine)
31 this.enabled = false;//Only enable inter/extrapol for remote players
32 }
33
34 void OnPhotonSerializeView(PhotonStream stream, PhotonMessageInfo info)
35 {
36 // Always send transform (depending on reliability of the network view)
37 if (stream.isWriting)
38 {
39 Vector3 pos = transform.localPosition;
40 Quaternion rot = transform.localRotation;
41 stream.Serialize(ref pos);
42 stream.Serialize(ref rot);
43 }
44 // When receiving, buffer the information
45 else
46 {
47 // Receive latest state information
48 Vector3 pos = Vector3.zero;
49 Quaternion rot = Quaternion.identity;
50 stream.Serialize(ref pos);
51 stream.Serialize(ref rot);
52
53 // Shift buffer contents, oldest data erased, 18 becomes 19, ... , 0 becomes 1
54 for (int i = m_BufferedState.Length - 1; i >= 1; i--)
55 {
56 m_BufferedState[i] = m_BufferedState[i - 1];
57 }
58
59
60 // Save currect received state as 0 in the buffer, safe to overwrite after shifting
61 State state;
62 state.timestamp = info.timestamp;
63 state.pos = pos;
64 state.rot = rot;
65 m_BufferedState[0] = state;
66
67 // Increment state count but never exceed buffer size
68 m_TimestampCount = Mathf.Min(m_TimestampCount + 1, m_BufferedState.Length);
69
70 // Check integrity, lowest numbered state in the buffer is newest and so on
71 for (int i = 0; i < m_TimestampCount - 1; i++)
72 {
73 if (m_BufferedState[i].timestamp < m_BufferedState[i + 1].timestamp)
74 Debug.Log("State inconsistent");
75 }
76 }
77 }
78
79 // This only runs where the component is enabled, which is only on remote peers (server/clients)
80 void Update()
81 {
82 double currentTime = PhotonNetwork.time;
83 double interpolationTime = currentTime - interpolationBackTime;
84 // We have a window of interpolationBackTime where we basically play
85 // By having interpolationBackTime the average ping, you will usually use interpolation.
86 // And only if no more data arrives we will use extrapolation
87
88 // Use interpolation
89 // Check if latest state exceeds interpolation time, if this is the case then
90 // it is too old and extrapolation should be used
91 if (m_BufferedState[0].timestamp > interpolationTime)
92 {
93 for (int i = 0; i < m_TimestampCount; i++)
94 {
95 // Find the state which matches the interpolation time (time+0.1) or use last state
96 if (m_BufferedState[i].timestamp <= interpolationTime || i == m_TimestampCount - 1)
97 {
98 // The state one slot newer (<100ms) than the best playback state
99 State rhs = m_BufferedState[Mathf.Max(i - 1, 0)];
100 // The best playback state (closest to 100 ms old (default time))
101 State lhs = m_BufferedState[i];
102
103 // Use the time between the two slots to determine if interpolation is necessary
104 double length = rhs.timestamp - lhs.timestamp;
105 float t = 0.0F;
106 // As the time difference gets closer to 100 ms t gets closer to 1 in
107 // which case rhs is only used
108 if (length > 0.0001)
109 t = (float)((interpolationTime - lhs.timestamp) / length);
110
111 // if t=0 => lhs is used directly
112 transform.localPosition = Vector3.Lerp(lhs.pos, rhs.pos, t);
113 transform.localRotation = Quaternion.Slerp(lhs.rot, rhs.rot, t);
114 return;
115 }
116 }
117 }
118 // Use extrapolation. Here we do something really simple and just repeat the last
119 // received state. You can do clever stuff with predicting what should happen.
120 else
121 {
122 State latest = m_BufferedState[0];
123
124 transform.localPosition = Vector3.Lerp(transform.localPosition, latest.pos, Time.deltaTime * 20 );
125 transform.localRotation = latest.rot;
126 }
127 }
128 }
NOTE: Network interpolation is affected by the network sendRate.
By default this is 10 timessecond for OnSerialize. (See PhotonNetwork.sendIntervalOnSerialize)
Raise the sendrate if you want to lower the interpolationBackTime.
We store twenty states with "playback" information
Keep track of what slots are used
this.enabled = false;Only enable interextrapol for remote players
Always send transform (depending on reliability of the network view)
When receiving, buffer the information
Receive latest state information
Shift buffer contents, oldest data erased, 18 becomes 19, ... , 0 becomes 1
Save currect received state as 0 in the buffer, safe to overwrite after shifting
Increment state count but never exceed buffer size
Check integrity, lowest numbered state in the buffer is newest and so on
This only runs where the component is enabled, which is only on remote peers (serverclients)
We have a window of interpolationBackTime where we basically play
By having interpolationBackTime the average ping, you will usually use interpolation.
And only if no more data arrives we will use extrapolation
Use interpolation
Check if latest state exceeds interpolation time, if this is the case then
it is too old and extrapolation should be used
Find the state which matches the interpolation time (time+0.1) or use last state
The state one slot newer (<100ms) than the best playback state
The best playback state (closest to 100 ms old (default time))
Use the time between the two slots to determine if interpolation is necessary
As the time difference gets closer to 100 ms t gets closer to 1 in
which case rhs is only used
if t=0 => lhs is used directly
Use extrapolation. Here we do something really simple and just repeat the last
received state. You can do clever stuff with predicting what should happen.